<template>
  <div class="Monaco-editor relative h-full w-full overflow-hidden" ref="el"></div>
</template>

<script lang="ts" setup>
  import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue';
  import * as monaco from 'monaco-editor';
  // import { GithubBoard } from './editor-themes';

  import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
  import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
  import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker';
  import { language as sqlLanguage } from 'monaco-editor/esm/vs/basic-languages/sql/sql.js';
  import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn';
  import { useAppStore } from '/@/store/modules/app';
  import { useDebounceFn } from '@vueuse/core';
  import { MODE, CodeMirrorInstance } from '../typing';
  const appStore = useAppStore();

  self.MonacoEnvironment = {
    getWorker(_, label) {
      if (label === 'json') {
        return new JsonWorker();
      }

      if (['typescript', 'javascript'].includes(label)) {
        return new tsWorker();
      }

      return new EditorWorker();
    },
  };

  const props = defineProps({
    value: String,
    mode: {
      type: String as PropType<MODE>,
      default: MODE.JSON,
      validator(value: any) {
        // 这个值必须匹配下列字符串中的一个
        return Object.values(MODE).includes(value);
      },
    },
    readonly: { type: Boolean },
  });

  const emit = defineEmits(['register', 'change']);

  const debounceRefresh = useDebounceFn(refresh, 100);

  const el = ref();

  let instance: monaco.editor.IStandaloneCodeEditor | null;

  onMounted(async () => {
    await nextTick();
    init();
    useWindowSizeFn(debounceRefresh);
  });

  watch(
    () => appStore.getDarkMode,
    async () => {
      setTheme();
    },
  );

  watch(
    () => props.value,
    async (value) => {
      await nextTick();

      const oldValue = instance?.getValue();
      if (value !== oldValue) {
        instance?.setValue(value ? value : '');
      }
    },
    { flush: 'post' },
  );
  watch(
    () => props.mode,
    async (value) => {
      await nextTick();

      instance && monaco.editor?.setModelLanguage(instance.getModel()!, value);
    },
    { flush: 'post' },
  );

  function init() {
    monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
      noSemanticValidation: true,
      noSyntaxValidation: false,
    });
    monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
      target: monaco.languages.typescript.ScriptTarget.ES2020,
      allowNonTsExtensions: true,
    });
    monaco.languages.registerCompletionItemProvider('sql', {
      provideCompletionItems() {
        const suggestions: any = [];
        // 这个 keywords 就是sql.js文件中有的
        sqlLanguage.keywords.forEach((item: any) => {
          suggestions.push({
            label: item,
            kind: monaco.languages.CompletionItemKind.Keyword,
            insertText: item,
          });
        });
        sqlLanguage.operators.forEach((item: any) => {
          suggestions.push({
            label: item,
            kind: monaco.languages.CompletionItemKind.Operator,
            insertText: item,
          });
        });
        sqlLanguage.builtinFunctions.forEach((item: any) => {
          suggestions.push({
            label: item,
            kind: monaco.languages.CompletionItemKind.Function,
            insertText: item,
          });
        });
        sqlLanguage.builtinVariables.forEach((item: any) => {
          suggestions.push({
            label: item,
            kind: monaco.languages.CompletionItemKind.Variable,
            insertText: item,
          });
        });
        return {
          // 最后要返回一个数组
          suggestions,
        };
      },
    });
    instance = monaco.editor.create(el.value, {
      // model: jsonModel,
      language: props.mode || 'javascript',
      tabSize: 2,
      fontSize: 16,
      lineNumbersMinChars: 2,
      lineDecorationsWidth: 4,
      automaticLayout: true,
      scrollBeyondLastLine: false,
      overviewRulerBorder: false,
      wordWrap: 'on',
      minimap: {
        enabled: false,
      },
      readOnly: props.readonly,
      theme: appStore.getDarkMode === 'light' ? 'vs' : 'vs-dark',
    });

    instance.setValue(props.value || '');
    instance.onDidChangeModelContent(() => {
      const value = instance?.getValue();
      emit('change', value);
    });
  }
  function refresh() {
    instance?.layout();
  }
  async function setTheme() {
    await nextTick();
    const theme = appStore.getDarkMode === 'light' ? 'vs' : 'vs-dark';

    instance?.updateOptions({
      theme,
    });
  }

  onUnmounted(() => {
    instance && instance.dispose(); // 销毁
    instance = null;
  });

  const methods: CodeMirrorInstance = {
    refresh,
  };

  emit('register', methods);
  defineExpose({ refresh });
</script>
